   var Util = (function() {
       var isType = function(type) {
           return function(data) {
               return Object.prototype.toString.apply(data) == '[object' + ' ' + type + ']';
           }
       }
       var isObject = isType('Object');
       var isArray = Array.isArray || isType('Array');

       function baseExtend(target, source, deep) {
           for (let key in source) {
               if (deep && (isObject(source[key]) || isArray(source[key]))) {
                   if (isObject(source[key]) && !isObject(target[key]))
                       target[key] = {};
                   if (isArray(source[key]) && !isArray(target[key]))
                       target[key] = [];
                   baseExtend(target[key], source[key], deep);
               } else if (source[key] !== undefined) {
                   target[key] = source[key];
               }
           }
       }

       var extend = function(target) {
           var deep, args = [].slice.call(arguments, 1)
           if (typeof target == 'boolean') {
               deep = target
               target = args.shift()
           }
           args.forEach(function(arg) { baseExtend(target, arg, deep) })
           return target;
       }

       var sendLog = function(baseUrl, params) {
           var id = '__log' + Date.now() + Math.random().toString(36).slice(-5),
               img = window[id] = new Image();
           img.onload = img.onerror = function() {
               if (window[id]) {
                   window[id] = null;
                   delete window[id];
               }
           };
           var query = [];
           for (var key in params) {
               query.push(encodeURIComponent(key) + "=" + encodeURIComponent(params[key]));
           }
           img.src = baseUrl + (baseUrl.indexOf('?') > -1 ? '&' : '?') + query.join('&');
       }

       var hamal = null;
       var isLoading = false;
       var queue = [];
       var sendLogSync = function(baseUrl, params) {
           var query = [];
           for (var key in params) {
               query.push(encodeURIComponent(key) + "=" + encodeURIComponent(params[key]));
           }
           var url = baseUrl + (baseUrl.indexOf('?') > -1 ? '&' : '?') + query.join('&');

           function request(url) {
               var _this = this;
               if (!hamal) {
                   hamal = document.createElement('img');

                   hamal.style.visibility = 'hidden';
                   hamal.style.width = hamal.style.height = '1px';
                   hamal.style.position = 'absolute';
                   hamal.style.left = '-1000px';
                   document.body.appendChild(hamal);

                   hamal.onload = hamal.onerror = function() {
                       isLoading = false;
                       if (queue.length > 0) {
                           request(queue.shift());
                       }
                   };
               }
               if (isLoading) {
                   queue.push(url);
               }

               isLoading = true;
               hamal.src = url;
           }
           request(url);
       }

       var getQuery = function(param, url) {
           url = (url || location.href).replace(/#.*$/, '');
           var queries = url.substring(url.indexOf('?') + 1).split('&') || [];
           var result = {};
           for (var item, i = 0, len = queries.length; i < len; i++) {
               item = queries[i].split('=');
               result[decodeURIComponent(item[0])] = decodeURIComponent(item[1]);
           };
           return param ? result[param] || '' : result;
       }

       // 兼容forEach
       if (!Array.prototype.forEach) {
           Array.prototype.forEach = function(callback, thisArg) {
               var T, k;
               if (this == null) {
                   throw new TypeError(' this is null or not defined');
               }
               var O = Object(this);
               var len = O.length >>> 0;
               if (typeof callback !== "function") {
                   throw new TypeError(callback + ' is not a function');
               }
               if (arguments.length > 1) {
                   T = thisArg;
               }
               k = 0;
               while (k < len) {
                   var kValue;
                   if (k in O) {
                       kValue = O[k];
                       callback.call(T, kValue, k, O);
                   }
                   k++;
               }
           };
       }

       return {
           isObject: isObject,
           isArray: isArray,
           extend: extend,
           sendLog: sendLog,
           getQuery: getQuery,
           sendLogSync: sendLogSync
       }
   }());


   function CPC(config) {
       this.CID = 59;
       this.PID = 356;
       this.st = +new Date;
       this.CLICK_URL = config.CLICK_URL || 'http://e.tf.360.cn/b/click';
       this.PV_URL = config.PV_URL || 'http://e.tf.360.cn/b/pv';
       this.data = config.data || {};
       this.m = config.m || Util.getQuery('m');
       this.m2 = config.m2 || Util.getQuery('m2');
       this._init();
   }

   CPC.prototype._init = function() {
       this._checkData(this.data);
   }

   CPC.prototype._checkData = function(data) {
       if (!Util.isObject(data)) {
           throw 'config Data must be Object';
       }
       for (let key in data) {
           var item = data[key];
           if (!item['asin']) {
               throw 'asin must be Config in Data';
           }
       }
   }

   CPC.prototype.addData = function(data) {
       this._checkData(data);
       this.data = Util.extend({}, this.data, data);
   }

   CPC.prototype.pv = function(sids) {

       var _this = this;
       if (!Util.isArray(sids) && !Util.isObject(sids)) {
           throw 'pv param must be Array or Object';
       }
       var startTime = Date.now();
       var params = {
           mid: this.m,
           m2: this.m2,
           pid: this.PID,
           cid: this.CID,
           st: startTime // 广告开始展示时间. 单位：毫秒(13位整型)
       };
       var pvData = [];
       if (Util.isObject(sids)) {
           sids = [sids];
       }
       sids.forEach(function(item, index) {
           var data = _this.data[item.sid];
           if (data) {
               data['st'] = startTime;
               data['index'] = item['index'] || 0;
               pvData.push({
                   adindex: data['index'],
                   asin: data['asin']
               })
           }
       })
       if (pvData.length > 0) {
           // ie10 + 支持
           if (window.atob) {
               var xhr = new XMLHttpRequest();
               params = Util.extend(params, { asin: JSON.stringify(pvData) });
               var query = [];
               for (var key in params) {
                   query.push(encodeURIComponent(key) + "=" + encodeURIComponent(params[key]));
               }
               //  debugger;
               var xhrUrl = this.PV_URL + (this.PV_URL.indexOf('?') > -1 ? '&' : '?') + query.join('&');
               xhr.open("POST", xhrUrl, true);
               xhr.send();
           }
           // ie9 及以下
           else {
               while (pvData.length) {
                   var part = pvData.splice(0, 3);
                   Util.sendLogSync(this.PV_URL, Util.extend(params, { asin: JSON.stringify(part) }));
               }
           }
       }
   }
   CPC.prototype.ck = function(sid, options) {
       var data = this.data[sid];
       options = options || {};
       if (data && data['asin']) {
           var now = +new Date;
           var params = {
               asin: data['asin'],
               st: data['st'] || this.st,
               ct: options['ct'] || now, // 用户点下时间. 单位：毫秒(13位整型)
               ut: options['ut'] || now + 300, // 用户抬起时间. 单位：毫秒(13位整型)
               adindex: data['index'] || options['index'] || 0,
               from: options['detail'] ? 1 : 2,
               mid: this.m,
               m2: this.m2
           };
           Util.sendLog(this.CLICK_URL, params);
       }
   }
   module.exports = CPC;